﻿using Elsa.Expressions.Contracts;
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Attributes;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
using Elsa.Workflows.UIHints;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Expression.Entity;
using T.FAS.Runtime.MF.Activities.Extensions;
using T.FAS.Runtime.MF.Dao;
using T.FAS.Runtime.MF.Entity;
using T.FAS.Runtime.MF.SPI;
using T.ServiceComponent.Kernel.Service;

namespace T.FAS.Runtime.MF.Activities
{
    public class CDOActivity : FASCodeActivity<object?>
    {
        public CDOActivity() { }

        // CDO的ID
        [Elsa.Workflows.Attributes.Input(Description = "CDO Code",UIHint = InputUIHints.SingleLine,Order = 1)]
        public string CDOID { get; set; }


        [Input(Description = "操作类型",
              Options = new[] { "GetDataByID", "Create", "BatchCreate", "Update", "BatchUpdate", "BatchEditUpdate", "Delete","BatchDelete","FireEvent"},
              DefaultValue = "GetDataByID",UIHint = InputUIHints.DropDown, Order = 2
          )]
        public string ActionType { get; set; }

     
        [Input(Description = "The cases to evaluate.", UIHint = "switch-editor",Order = 3)]
        public IList<BranchCondition> ParamList { get; set; }
        /// <summary>
        /// 节点默认输出的变量
        /// </summary>
        [Output(Description = "节点输出的变量")]
        //public List<Variable> OutputVariables { get; set; }
        public Dictionary<string, Variable> OutputVariables { get; set; }

        public override List<Variable> ActivityOutputVariables { get { return OutputVariables != null ? OutputVariables.Values.ToList() : new List<Variable>(); } }

        protected override async void Execute(ActivityExecutionContext context)
        {
            try
            {
               
                var v = context.GetVariableValues();
                LogUtil.Log("当前变量为：" + JsonConvert.SerializeObject(v));

                var script = await ParseScript(context);
                LogUtil.Log("CDO执行脚本为：" + script);

                await ExecuteScript(context, script);
            }
            catch (Exception ex)
            {
                await context.FaultAndComplete(ex, this);
            }

        }

        private async Task ExecuteScript(ActivityExecutionContext context,string script )
        {
            // var expService = context.GetRequiredService<IFasExpService>();
            var factory = context.GetService<Func<string, IFasExpService>>();
            var expService = factory("publish");

            var extraParams = CallContext.GetData("WorkflowDebugParam");
            //调试模式
            if (extraParams != null)
            {
                expService = factory("debug");
            }
            var result = expService.Debug(script, new Dictionary<string, object>(), extraParams != null ? (extraParams as Dictionary<string, string>) : null);
            LogUtil.Log("CDO执行结果为" + JsonConvert.SerializeObject(result));
            var outputInstanceValues = new Dictionary<string, object>();

            if (result != null)
            {
                //成功
                if (result.State == Expression.Entity.ResultState.Success)
                {
                   
                    //此处为输出变量赋值，实际上只有一个返回变量record
                    if (OutputVariables != null && result.Result != null)
                    {
                        var resultValue = ProcessResultValue(result);
                        foreach (var variableName in OutputVariables.Keys)
                        {
                            var item = OutputVariables[variableName];
                            context.SetVariable(item.Name, resultValue);

                            //向迭代返回值数组中赋值,这里会累计每次迭代的执行结果，返回到数组中
                            context.SetIterationVariableValue(item.Name, resultValue);

                            //给输出参数赋值
                            outputInstanceValues[variableName] = resultValue;
                        }
                        this.OutputInstanceValues[context.Id] = outputInstanceValues;
                    }

                    foreach (var outcome in DoneOutcomes ?? new List<string>())
                    {
                        await context.CompleteActivityWithOutcomesAsync(new[] { outcome });
                    }
                }
                else
                {
                    var exception = new Exception(result.ErrMsg);
                    LogUtil.Log($"执行CDO发生异常：{result.ErrMsg}");
                    await context.FaultAndComplete(exception, this);
                }
            }
            context.SetResult(result);
        }
        private object ProcessResultValue(ExprResult result)
        {
            object? resultValue = null;
            LogUtil.Log($"Action.result.Result.Type={result.Result.GetType()},result.Result as List<object>={result.Result as List<object>}");
           
             if (result.Result is JObject || result.Result is JToken)
            {
                resultValue = JArrayExtensions.ConvertJToken(result.Result as JToken);
            }
            if (result.Result is TRecord )
            {
                var record = result.Result as TRecord;
                resultValue = JArrayExtensions.ConvertJToken(TRecord.ToJson(record));
            }
            return resultValue;
        }
        private async Task<string> ParseScript(ActivityExecutionContext context)
        {
            string script = string.Empty;
            var expressionEvaluator = context.GetRequiredService<IExpressionEvaluator>();
            var inputInstanceValues = new Dictionary<string, object>();
            LogUtil.Log($"CDO.ParseScript：{JsonConvert.SerializeObject(ParamList)}");
            if (ActionType== "GetDataByID")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<string>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"CDO.GetDataByID('{CDOID}','{conditionValue}').Record";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["Id"] = conditionValue;
            }
            else if (ActionType == "Create")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"let cdo = {JsonConvert.SerializeObject(conditionValue)}; CDO.Create('{CDOID}',cdo).Record";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["record"] = conditionValue;
            }
            else if (ActionType == "BatchCreate")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"let dataList = {JsonConvert.SerializeObject(conditionValue)}; CDO.BatchCreate('{CDOID}',dataList)";
            }
            else if (ActionType == "Update")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"let cdo = {JsonConvert.SerializeObject(conditionValue)}; CDO.Update('{CDOID}',cdo).Record";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["record"] = conditionValue;
            }
            else if (ActionType == "BatchUpdate")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"let dataList = {JsonConvert.SerializeObject(conditionValue)}; CDO.BatchUpdate('{CDOID}',dataList)";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["dataList"] = conditionValue;
            }
            else if (ActionType == "BatchEditUpdate")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"let dataList = {JsonConvert.SerializeObject(conditionValue)}; CDO.BatchEditUpdate('{CDOID}',dataList)";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["dataList"] = conditionValue;
            }
            else if (ActionType == "Delete")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<string>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"CDO.Delete('{CDOID}','{conditionValue}')";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["Id"] = conditionValue;
            }
            else if (ActionType == "BatchDelete")
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(ParamList.FirstOrDefault().Condition, context.ExpressionExecutionContext);

                script = $"let dataIdList = {conditionValue};CDO.BatchDelete('{CDOID}',dataIdList)";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["Id"] = conditionValue;
            }
            else if (ActionType == "FireEvent")
            {
                var colKey = await expressionEvaluator.EvaluateAsync<string>(ParamList.FirstOrDefault(t=>t.Label== "ColKey")?.Condition, context.ExpressionExecutionContext);
                var eventKey = await expressionEvaluator.EvaluateAsync<string>(ParamList.FirstOrDefault(t => t.Label == "EventKey")?.Condition, context.ExpressionExecutionContext);
                var billId = await expressionEvaluator.EvaluateAsync<string>(ParamList.FirstOrDefault(t => t.Label == "BillId")?.Condition, context.ExpressionExecutionContext);

                script = $"CDO.FireEvent('{CDOID}','{colKey}','{eventKey}','{billId}')";
                //给入参实时数据赋值
                inputInstanceValues["cdoId"] = CDOID;
                inputInstanceValues["colKey"] = colKey;
                inputInstanceValues["eventKey"] = eventKey;
                inputInstanceValues["billId"] = billId;
            }
            this.InputInstanceValues[context.Id] = inputInstanceValues;
            return script;
        }
    }
}
